// Copyright Epic Games, Inc. All Rights Reserved.

#include "class05GameModeBase.h"
#include <Engine/StaticMeshActor.h>
#include <StaticMeshDescription.h>
#include <StaticMeshAttributes.h>
#include <EngineUtils.h>
#include <vector>
#include <fstream>
#include <iostream>

void Aclass05GameModeBase::StartPlay()
{
    for (TActorIterator<AStaticMeshActor> itr(GetWorld()); itr; ++itr)
    {
        AStaticMeshActor* mesh = *itr;
        if (mesh->GetName() == "Table") AnalyseStaticMesh(mesh);
    }
    AGameModeBase::StartPlay();
}

void Aclass05GameModeBase::AnalyseStaticMesh(AStaticMeshActor* mesh)
{
    UStaticMeshComponent* component = mesh->GetStaticMeshComponent();
    UStaticMesh* meshData = component->GetStaticMesh();
    if (meshData)
    {
        int numLOD = meshData->GetNumLODs();
        int numVertices = meshData->GetNumVertices(0);
        int numTriangles = meshData->GetNumTriangles(0);
        UE_LOG(LogTemp, Warning, TEXT("%s: LOD = %d, Vertices = %d, Triangles = %d"),
               *meshData->GetName(), numLOD, numVertices, numTriangles);

        std::ofstream out("output.obj");
        std::vector<FVector3f> outPositions, outNormals;
        std::vector<FVector2f> outUVs;

        UStaticMeshDescription* desc = meshData->GetStaticMeshDescription(0);
        const TVertexAttributesRef<FVector3f>& positions = desc->GetVertexPositions();
        const TAttributesSet<FVertexInstanceID>& attributes = desc->VertexInstanceAttributes();
        TPolygonGroupAttributesConstRef<FName> materials = desc->GetPolygonGroupMaterialSlotNames();
        
        // Traverse all vertex attributes and triangles
        for (int i = 0; i < desc->GetPolygonGroupCount(); ++i)
        {
            TArray<FPolygonID> polygons;
            desc->GetPolygonGroupPolygons(i, polygons);
            UE_LOG(LogTemp, Warning, TEXT("%d: PolygonCount = %d, Material = %s"),
                   i, polygons.Num(),  *materials[i].ToString());

            for (FPolygonID pID : polygons)
            {
                TArray<FTriangleID> triangles;
                desc->GetPolygonTriangles(pID, triangles);
                for (FTriangleID tID : triangles)
                {
                    TArray<FVertexInstanceID> instanceIDs;
                    desc->GetTriangleVertexInstances(tID, instanceIDs);
                    for (int t = 0; t < 3; ++t)
                    {
                        FVertexInstanceID instanceID = instanceIDs[t];
                        FVertexID vID = desc->GetVertexInstanceVertex(instanceID);
                        FVector3f pos = positions[vID];
                        FVector3f norm = attributes.GetAttribute<FVector3f>(instanceID,
                            MeshAttribute::VertexInstance::Normal, 0);
                        FVector2f uv = attributes.GetAttribute<FVector2f>(instanceID,
                            MeshAttribute::VertexInstance::TextureCoordinate, 0);

                        outPositions.push_back(pos);
                        outNormals.push_back(norm);
                        outUVs.push_back(uv);
                    }
                }
            }
        }

        // Output to OBJ file
        out << "# Exported from Unreal: " << TCHAR_TO_UTF8(*mesh->GetName()) << std::endl;
        for (size_t i = 0; i < outPositions.size(); ++i)
        {
            const FVector3f& v = outPositions[i];
            out << "v " << v[0] << " " << v[1] << " " << v[2] << std::endl;
        }

        for (size_t i = 0; i < outNormals.size(); ++i)
        {
            const FVector3f& n = outNormals[i];
            out << "vn " << n[0] << " " << n[1] << " " << n[2] << std::endl;
        }

        for (size_t i = 0; i < outUVs.size(); ++i)
        {
            const FVector2f& uv = outUVs[i];
            out << "vt " << uv[0] << " " << uv[1] << std::endl;
        }

        for (size_t i = 0; i < outPositions.size(); i += 3)
            out << "f " << (i + 1) << " " << (i + 2) << " " << (i + 3) << std::endl;
        UE_LOG(LogTemp, Warning, TEXT("Output to OBJ file: Vertices = %d"), (int)outPositions.size());
    }
}
